/*
 * mpgfx.c
 *
 *  Created on: 2012-04-11
 *      Author: Aco
 */

#include "SDL/SDL.h"
#include "../log.h"

#include <math.h>

const int LCDW = 128;
const int LCDH = 64;
const int LCDBW = 16;
const int LCDBH = 8;
const int LCD_SCALE = 4;

SDL_Surface* screen = NULL;
SDL_Rect scrRect;

const unsigned int PIX_ON = 0xA0C0FF;
const unsigned int PIX_OFF = 0xFF0000B0;
const unsigned char EIGHT_BITS[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };

void Glcd_Init()
{
	screen = SDL_SetVideoMode(LCDW * LCD_SCALE, LCDH * LCD_SCALE, 32, SDL_SWSURFACE);
	if(screen == NULL)
	{
		_EMU_log("Video init failed, reason : %s", SDL_GetError());
		SDL_Quit();
	}
	else
	{
		_EMU_log("Display window opened");
	}

	scrRect.x = 0;
	scrRect.y = 0;
	scrRect.w = LCDW * LCD_SCALE;
	scrRect.h = LCDH * LCD_SCALE;
}

void _EMU_GFX_tick()
{
	SDL_Flip(screen);
}

void _EMU_GFX_slowUpdate()
{
	SDL_Flip(screen);
	SDL_Delay(20);
}

void _EMU_GFX_fastUpdate()
{
	SDL_Flip(screen);
	SDL_Delay(5);
}

void _EMU_DotNoFlip(unsigned char x, unsigned char y, char color)
{
	SDL_Rect rect;
	rect.x = x * LCD_SCALE;
	rect.y = y * LCD_SCALE;
	rect.w = LCD_SCALE;
	rect.h = LCD_SCALE;
	SDL_FillRect(screen, &rect, color ? PIX_ON : PIX_OFF);
}

void _EMU_charPatternH(unsigned char x, unsigned char y, unsigned char c, int l)
{
	int i = 0;
	for(i = 0; i < l; ++i)
		_EMU_DotNoFlip(x + i, y, EIGHT_BITS[7 - i] & c);
}

void _EMU_charPatternV(unsigned char x, unsigned char y, unsigned char c, int l)
{
	int i = 0;
	for(i = 0; i < l; ++i)
		_EMU_DotNoFlip(x, y + i, EIGHT_BITS[i] & c);
}

void Glcd_Fill(unsigned char pattern)
{
	SDL_FillRect(screen, &scrRect, pattern ? PIX_ON : PIX_OFF);
	_EMU_GFX_tick();
}

void Glcd_fill(unsigned char pattern)
{
	SDL_FillRect(screen, &scrRect, pattern ? PIX_ON : PIX_OFF);
	_EMU_GFX_tick();
}

void Glcd_Image(const unsigned char * img)
{
	int x, y, i = 0;

	for(y = 0; y < LCDBH; ++y)
	{
		for(x = 0; x < LCDW; ++x)
		{
			_EMU_charPatternV(x, y * 8, img[i], 8);
			++i;
		}
	}

	_EMU_GFX_slowUpdate();
}

void Glcd_PartialImage(unsigned char ox, unsigned char oy,
		unsigned char dw, unsigned char dh,
		unsigned char srcw, char srch,
		const unsigned char * img)
{
	int x, y; // i = 0;

	for(y = 0; y < (dh + 7) / 8; ++y)
	{
		for(x = 0; x < dw; ++x)
		{
			if(y + 8 > srch)
				_EMU_charPatternV(ox + x, oy + y * 8, img[y * srcw + x], 8 - (y + 8 - srch));
			else
				_EMU_charPatternV(ox + x, oy + y * 8, img[y * srcw + x], 8);
			//++i;
		}
	}

	_EMU_GFX_slowUpdate();
}

void Glcd_Dot(unsigned char x, unsigned char y, char color)
{
	SDL_Rect rect;
	rect.x = x * LCD_SCALE;
	rect.y = y * LCD_SCALE;
	rect.w = LCD_SCALE;
	rect.h = LCD_SCALE;
	SDL_FillRect(screen, &rect, color ? PIX_ON : PIX_OFF);
}

void Glcd_Box(unsigned char x, unsigned char y, unsigned char w, unsigned char h, char color)
{
	SDL_Rect rect;
	rect.x = x * LCD_SCALE;
	rect.y = y * LCD_SCALE;
	rect.w = (w - x) * LCD_SCALE;
	rect.h = (h - y) * LCD_SCALE;
	SDL_FillRect(screen, &rect, color ? PIX_ON : PIX_OFF);
	_EMU_GFX_slowUpdate();
}

void Glcd_V_Line(unsigned char y1, unsigned char y2, unsigned char x, char color)
{
	SDL_Rect rect;
	rect.x = x * LCD_SCALE;
	rect.y = y1 * LCD_SCALE;
	rect.w = LCD_SCALE;
	rect.h = (y2 - y1) * LCD_SCALE;
	SDL_FillRect(screen, &rect, color ? PIX_ON : PIX_OFF);
	_EMU_GFX_fastUpdate();
}

void Glcd_H_Line(unsigned char x1, unsigned char x2, unsigned char y, char color)
{
	SDL_Rect rect;
	rect.x = x1 * LCD_SCALE;
	rect.y = y * LCD_SCALE;
	rect.w = (x2 - x1) * LCD_SCALE;
	rect.h = LCD_SCALE;
	SDL_FillRect(screen, &rect, color ? PIX_ON : PIX_OFF);
	_EMU_GFX_fastUpdate();
}

void Glcd_Rectangle(unsigned char x, unsigned char y, unsigned char w, unsigned char h, char color)
{
	SDL_Rect rect;
	int rc = color ? PIX_ON : PIX_OFF;

	rect.x = x * LCD_SCALE;
	rect.y = y * LCD_SCALE;
	rect.w = (w - x) * LCD_SCALE;
	rect.h = LCD_SCALE;
	SDL_FillRect(screen, &rect, rc);

	rect.x = x * LCD_SCALE;
	rect.y = (h - 1) * LCD_SCALE;
	rect.w = (w - x) * LCD_SCALE;
	rect.h = LCD_SCALE;
	SDL_FillRect(screen, &rect, rc);

	rect.x = x * LCD_SCALE;
	rect.y = y * LCD_SCALE;
	rect.w = LCD_SCALE;
	rect.h = (h - y) * LCD_SCALE;
	SDL_FillRect(screen, &rect, rc);

	rect.x = (w - 1) * LCD_SCALE;
	rect.y = y * LCD_SCALE;
	rect.w = LCD_SCALE;
	rect.h = (h - y) * LCD_SCALE;
	SDL_FillRect(screen, &rect, rc);

	_EMU_GFX_slowUpdate();
}

void Glcd_Rectangle_Round_Edges(unsigned char x, unsigned char y, unsigned char w, unsigned char h, unsigned char rad, char color)
{
	Glcd_Rectangle(x, y, w, h, color);
}

void Glcd_Rectangle_Round_Edges_Fill(unsigned char x, unsigned char y, unsigned char w, unsigned char h, unsigned char rad, char color)
{
	SDL_Rect rect;
	rect.x = x * LCD_SCALE;
	rect.y = y * LCD_SCALE;
	rect.w = (w - x) * LCD_SCALE;
	rect.h = (h - y) * LCD_SCALE;
	SDL_FillRect(screen, &rect, color ? PIX_ON : PIX_OFF);
	_EMU_GFX_slowUpdate();
}

void swap(unsigned char * a, unsigned char * b)
{
	unsigned char c = *a;
	*a = *b;
	*b = c;
}

void Glcd_Line(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, char color)
{
	int steep = abs(y1 - y0) > abs(x1 - x0);
	int x;
	int deltax;
	int deltay;
	float error;
	float deltaerr;
	int ystep;
	int y;

	if(steep)
	{
		swap(&x0, &y0);
		swap(&x1, &y1);
	}

	if(x0 > x1)
	{
		swap(&x0, &x1);
		swap(&y0, &y1);
	}

	deltax = x1 - x0;
	deltay = abs(y1 - y0);

	error = 0.0f;
	deltaerr = (float)deltay / (float)deltax;
	ystep = 0;
	y = y0;
	if (y0 < y1) ystep = 1; else ystep = -1;

	for (x = x0; x < x1; ++x)
	{
		if(steep)
		{
			Glcd_Dot(y, x, color);
		}
		else
		{
			Glcd_Dot(x, y, color);
		}

		error += deltaerr;
		if(error >= 0.5f)
		{
			y += ystep;
			error -= 1.0f;
		}
	}

	_EMU_GFX_slowUpdate();
}

void Glcd_Circle(unsigned char x0, unsigned char y0, short radius, char color)
{
	int f = 1 - radius;
	int ddF_x = 1;
	int ddF_y = -2 * radius;
	int x = 0;
	int y = radius;

	Glcd_Dot(x0, y0 + radius, color);
	Glcd_Dot(x0, y0 - radius, color);
	Glcd_Dot(x0 + radius, y0, color);
	Glcd_Dot(x0 - radius, y0, color);

	while(x < y)
	{
		// ddF_x == 2 * x + 1;
		// ddF_y == -2 * y;
		// f == x*x + y*y - radius*radius + 2*x - y + 1;
		if(f >= 0)
		{
			y--;
			ddF_y += 2;
			f += ddF_y;
		}
		x++;
		ddF_x += 2;
		f += ddF_x;
		Glcd_Dot(x0 + x, y0 + y, color);
		Glcd_Dot(x0 - x, y0 + y, color);
		Glcd_Dot(x0 + x, y0 - y, color);
		Glcd_Dot(x0 - x, y0 - y, color);
		Glcd_Dot(x0 + y, y0 + x, color);
		Glcd_Dot(x0 - y, y0 + x, color);
		Glcd_Dot(x0 + y, y0 - x, color);
		Glcd_Dot(x0 - y, y0 - x, color);
	}

	_EMU_GFX_slowUpdate();
}

void Glcd_Circle_Fill(unsigned char cx, unsigned char cy, short radius, char color)
{
	int x, y;
	float radsq = radius * radius;

	for(y = cy - radius; y <= cy + radius; ++y)
	{
		for(x = cx - radius; x <= cx + radius; ++x)
		{
			if(((x - cx) * (x - cx) + (y - cy) * (y - cy)) <= radsq)
			{
				Glcd_Dot(x, y, color);
			}
		}
	}

	_EMU_GFX_slowUpdate();
}

void Glcd_Set_Font(char fontID, char w, char h, char start)
{

}

void Glcd_Write_Text(const char * text, char a, char b, char c)
{

}


